#include "EditorProxy.h"
#include "EditorWidget.h"
#include "Settings.h"

#include <QApplication>
#include <QGraphicsProxyWidget>
#include <QTextStream>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QScrollBar>
#include <QTouchEvent>
#include <QTextBlock>
#include <QTextCursor>

EditorProxy::EditorProxy(QDeclarativeItem *parent)
    : QDeclarativeItem(parent)
    , m_editor(new EditorWidget())
    , m_totalScaleFactor(1.0)
    , m_scrollFactor(3.0)
{
    setAcceptTouchEvents(true);
    setAcceptedMouseButtons(Qt::LeftButton | Qt::RightButton | Qt::MiddleButton);
    setSmooth(true);
    //setFlag(QGraphicsItem::ItemClipsToShape, true);
    //setFlag(QGraphicsItem::ItemClipsChildrenToShape, true);
    //setFlag(QGraphicsItem::ItemSendsGeometryChanges, true);

    //m_editor->setAutoFillBackground(false);
    m_editor->setAttribute(Qt::WA_TranslucentBackground);

    m_proxyWidget = new QGraphicsProxyWidget(this);
    m_proxyWidget->setWidget(m_editor);

    connect(m_editor, SIGNAL(undoAvailable(bool)), this, SIGNAL(undoAvailable(bool)));
    connect(m_editor, SIGNAL(redoAvailable(bool)), this, SIGNAL(redoAvailable(bool)));
    connect(m_editor, SIGNAL(copyAvailable(bool)), this, SIGNAL(copyAvailable(bool)));
}

EditorProxy::~EditorProxy()
{
    delete m_editor;
}

void EditorProxy::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
{
    Q_UNUSED(oldGeometry)

    QRectF r(newGeometry);
    r.moveTopLeft(QPointF(0.0,0.0));
    m_proxyWidget->setGeometry(r);
}

bool EditorProxy::sceneEvent(QEvent *event)
{
    switch (event->type()) {
        case QEvent::TouchBegin:
        case QEvent::TouchUpdate:
        case QEvent::TouchEnd: {
            QTouchEvent *touchEvent = static_cast<QTouchEvent *>(event);
            QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
            if (touchPoints.count() == 1) {
                const QTouchEvent::TouchPoint &touchPoint0 = touchPoints.first();
                qreal x = (touchPoint0.pos().x() - touchPoint0.lastPos().x()) * m_scrollFactor * m_totalScaleFactor;
                qreal y = (touchPoint0.pos().y() - touchPoint0.lastPos().y()) * m_scrollFactor * m_totalScaleFactor;
                if (!qFuzzyCompare(x + 1, 1))
                    m_editor->horizontalScrollBar()->setValue(m_editor->horizontalScrollBar()->value() + x);
                if (!qFuzzyCompare(y + 1, 1))
                    m_editor->verticalScrollBar()->setValue(m_editor->verticalScrollBar()->value() + y);
            } else if (touchPoints.count() == 2) {
                const QTouchEvent::TouchPoint &touchPoint0 = touchPoints.first();
                const QTouchEvent::TouchPoint &touchPoint1 = touchPoints.last();
                qreal scaleFactor = QLineF(touchPoint0.pos(), touchPoint1.pos()).length() / QLineF(touchPoint0.startPos(), touchPoint1.startPos()).length();
                if (touchEvent->touchPointStates() & Qt::TouchPointReleased) {
                    m_totalScaleFactor *= scaleFactor;
                    scaleFactor = 1;
                }
                m_editor->setFontScale(m_totalScaleFactor * scaleFactor);
            }
            return true;
        }
        default:
            break;
    }
    return QDeclarativeItem::sceneEvent(event);
}

QString EditorProxy::imageFilePath(const QString &filename) const
{
    if (m_imageDirectory.isNull()) {
        QStringList args = QApplication::arguments();
        if (args.isEmpty())
            return QString();
        QFileInfo fi(args.first());
        QDir dir = fi.absoluteDir();
        if (!dir.cd(QLatin1String("images"))) {
            QDir defaultDir(QLatin1String("/opt/MeeTxtEdit/images/"));
            dir = defaultDir;
        }
        m_imageDirectory = dir.exists() ? dir.absolutePath() : QLatin1String("");
    }
    if (m_imageDirectory.isEmpty())
        return QString();
    return QFileInfo(m_imageDirectory, filename).absoluteFilePath();
}

void EditorProxy::undo()
{
    m_editor->undo();
}

void EditorProxy::redo()
{
    m_editor->redo();
}

void EditorProxy::cut()
{
    m_editor->cut();
}

void EditorProxy::copy()
{
    m_editor->copy();
}

void EditorProxy::paste()
{
    m_editor->paste();
}

void EditorProxy::clear()
{
    m_editor->clear();
    //m_editor->document()->clear();
    //m_editor->document()->clearUndoRedoStacks(QTextDocument::UndoAndRedoStacks);
}

bool EditorProxy::load(const QString &file)
{
    QFile f(file);
    if (!f.open(QIODevice::ReadOnly | QIODevice::Text))
        return false;
    QTextStream s(&f);
    m_editor->document()->setPlainText(s.readAll());
    //m_editor->setText(f.readAll());
    f.close();
    m_editor->setTextCursor(QTextCursor(m_editor->document()));
    m_editor->ensureCursorVisible();
    addRecent(file);
    return true;
}

bool EditorProxy::save(const QString &file)
{
    QFile f(file);
    if (!f.open(QIODevice::WriteOnly | QIODevice::Text))
        return false;
    QTextStream s(&f);
    s << m_editor->document()->toPlainText();
    s.flush();
    f.close();
    addRecent(file);
    return true;
}

void EditorProxy::addRecent(const QString &file)
{
    QStringList files;
    Q_FOREACH(const QVariant &v, Settings::instance()->valueList("recentFiles")) {
        QString s = v.toString();
        if (!s.isEmpty() && s != file)
            files.append(s);
    }
    files.prepend(file);
    int maxRecentFiles = Settings::instance()->value("maxRecentFiles", 25).toInt();
    while (files.count() > maxRecentFiles)
        files.pop_back();
    QVariantList list;
    Q_FOREACH(const QString &s, files)
        list.append(s);
    Settings::instance()->setValueList("recentFiles", list);
}

bool EditorProxy::searchPrevious(const QString &text)
{
    QTextDocument::FindFlags flags = QTextDocument::FindBackward;
    return m_editor->find(text, flags);
}

bool EditorProxy::searchNext(const QString &text)
{
    QTextDocument::FindFlags flags;
    return m_editor->find(text, flags);
}
